﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.IO;
using Microsoft.Win32;
using System.Xml.Linq;

namespace CCRPlanner {

    public partial class CCRPlannerMain : Window {

        private static List<SessionStats> sessions = new List<SessionStats>();
        private static List<Room> roomData = new List<Room>();
        
        private static String cacheFile = "ExampleSessionStats.xml";
        private static Int32 Days = 2;
        private static Int32 Rooms = 7;

        public CCRPlannerMain() {
            InitializeComponent();

            if (File.Exists(cacheFile)) {

                foreach (var s in SessionStats.LoadSessions(cacheFile)) {
                    sessions.Add(s);
                }
            }

            for (int i = 0; i < Days; i++)
                gRooms.RowDefinitions.Add(new RowDefinition());

            for (int i = 0; i < Rooms; i++)
                gRooms.ColumnDefinitions.Add(new ColumnDefinition());

            BuildRooms();

            SetRooms();
            UpdateConflicts();
        }
        
        private void BuildRooms() {
            for (int j = 0; j < Rooms; j++) {
                for (int i = Days - 1; i >= 0; i--) {
                    Room r = new Room() {
                        Day = i + 1,
                        RoomNumber = j + 1,
                        TimeBlocks = 5
                    };

                    Int32 offset = 0;
                    while (sessions.Count - offset > 0 && r.TimeRemaining) {
                        SessionStats s = sessions[0 + offset];
                        if (r.HaveTime(s)) {
                            r.Sessions.Add(s);
                            sessions.RemoveAt(0 + offset);
                        }
                        else {
                            offset++;
                        }
                    }

                    roomData.Add(r);
                }
            }
        }

        private void SetRooms() {
            gRooms.Children.Clear();

            foreach (var r in roomData) {
                ContentControl c = new ContentControl();
                Grid.SetColumn(c, r.RoomNumber - 1);
                Grid.SetRow(c, r.Day - 1);
                c.Content = r;
                gRooms.Children.Add(c);
            }
        }

        private void UpdateConflicts() {
            foreach (Room r in roomData) {
                foreach (SessionStats s in r.Sessions) {
                    var matches = from rm in roomData
                                  where rm.Day == r.Day
                                  where rm.RoomNumber != r.RoomNumber
                                  where rm.GetSessionByBlock(s.Block) != null
                                  select rm.GetSessionByBlock(s.Block);

                    s.SetConflicts(matches);
                }
                r.RaisePropertyChanged("Conflicts");
            }
            Int32 c = roomData.Sum(x => x.Conflicts);
            lConflicts.Content = String.Format("Total Conflicts: {0}", c);
        }

        private void Room_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) {
            Button b = e.OriginalSource as Button;
            DockPanel dp = sender as DockPanel;
            if (b != null && dp != null) {

                String Command = b.Tag.ToString();
                Room r = dp.Tag as Room;
                ListView lv = null;
                foreach (object o in dp.Children) {
                    if (o is ListView) {
                        lv = (ListView)o;
                        break;
                    }
                }

                if (Command.Equals("REMOVE")) {
                    if (lv.SelectedIndex >= 0) {
                        sessions.Add(r.Sessions[lv.SelectedIndex]);
                        r.Sessions.RemoveAt(lv.SelectedIndex);
                        UpdateConflicts();
                    }
                }
                else if (Command.Equals("CONFLICT")) {
                    if (lv.SelectedIndex >= 0) {
                        String msg = String.Join(Environment.NewLine,
                            r.Sessions[lv.SelectedIndex].ConflictNames);
                        MessageBox.Show(msg, "Conflicts", MessageBoxButton.OK, MessageBoxImage.Information);
                    }
                }
                else if (Command.Equals("UP")) {
                    if (lv.SelectedIndex >= 1) {
                        Int32 idx = lv.SelectedIndex;
                        SessionStats s = r.Sessions[lv.SelectedIndex];
                        r.Sessions.RemoveAt(idx);
                        r.Sessions.Insert(idx - 1, s);
                        UpdateConflicts();
                        lv.SelectedIndex = idx - 1;
                    }
                }
                else if (Command.Equals("DOWN")) {
                    if (lv.SelectedIndex >= 0 && lv.SelectedIndex < lv.Items.Count - 1) {
                        Int32 idx = lv.SelectedIndex;
                        SessionStats s = r.Sessions[lv.SelectedIndex];
                        r.Sessions.RemoveAt(idx);
                        r.Sessions.Insert(idx + 1, s);
                        UpdateConflicts();
                        lv.SelectedIndex = idx + 1;
                    }
                }
                else if (Command.Equals("ADD")) {
                    AddSession asWin = new AddSession(sessions);
                    asWin.Owner = this;
                    asWin.ShowDialog();
                    if (asWin.SelectedSessionName != null) {
                        SessionStats s = sessions.First(x => x.SessionName.Equals(asWin.SelectedSessionName));
                        if (r.HaveTime(s)) {
                            r.Sessions.Add(s);
                            sessions.Remove(s);
                        }
                        UpdateConflicts();
                    }
                }
            }
        }

        private void bSaveData_Click(object sender, RoutedEventArgs e) {
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.FileName = "Schedule";
            dlg.DefaultExt = ".xml";
            dlg.Filter = "XML documents (.xml)|*.xml";

            Nullable<bool> result = dlg.ShowDialog();
            if (result == true) {
                IOTools.SerializeObject(dlg.FileName, roomData.GetType(), roomData);
            }
        }

        private void bLoadData_Click(object sender, RoutedEventArgs e) {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.FileName = "Schedule";
            dlg.DefaultExt = ".xml";
            dlg.Filter = "XML documents (.xml)|*.xml";

            Nullable<bool> result = dlg.ShowDialog();
            if (result == true) {
                List<Room> r = (List<Room>)IOTools.DeserializeObject(dlg.FileName, roomData.GetType());
                roomData.Clear();
                roomData.AddRange(r);
                SetRooms();
                UpdateConflicts();
            }
        }

        private void bExport_Click(object sender, RoutedEventArgs e) {
            XDocument export = new XDocument(
                    new XElement("Schedule",
                        from r in roomData
                        from s in r.Sessions
                        orderby r.RoomNumber
                        orderby r.Day
                        select new XElement("Session",
                            new XElement("Room", r.RoomName),
                            new XElement("Block", s.Block),
                            new XElement("Length", s.BlockLength),
                            new XElement("Speraker", s.Speaker),
                            new XElement("SessionName", s.SessionName)
                        )
                    )
                );

            SaveFileDialog dlg = new SaveFileDialog();
            dlg.FileName = "Export";
            dlg.DefaultExt = ".xml";
            dlg.Filter = "XML documents (.xml)|*.xml";

            Nullable<bool> result = dlg.ShowDialog();
            if (result == true) {
                export.Save(dlg.FileName);
            }
        }
    }
}
